package com.itheima.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson2.JSON;
import com.itheima.common.ThreadLocalUtil;
import com.itheima.common.ValidateCodeUtils;
import com.itheima.entity.dto.LocationDto;
import com.itheima.entity.dto.UserDto;
import com.itheima.entity.pojo.User;
import com.itheima.entity.vo.RecommendVo;
import com.itheima.entity.vo.UserVo;
import com.itheima.user.mapper.UserMapper;
import com.itheima.user.service.LocationService;
import com.itheima.user.service.NotificationSettingsService;
import com.itheima.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author :WuJunJie
 * packageName :com.itheima.user.service.impl
 * fileName :UserServiceImpl
 * creationTime :2022-12-12 17:11
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LocationService locationService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private NotificationSettingsService notificationSettingsService;

    @Override
    @Transactional
    public UserVo login(UserDto userDto) {
        String s = redisTemplate.opsForValue().get("tanhuaMsg:" + userDto.getPhone());
        if (s == null || !s.equals(userDto.getCode())) {
            throw new RuntimeException("短信验证码不正确");
        }
        UserVo userVo = new UserVo();
        userVo.setIsFirst(false);
        User user = userMapper.selectByPhone(userDto.getPhone());
        if (user == null) {
            user = new User();
            BeanUtils.copyProperties(userDto, user);
            user.setId(IdUtil.getSnowflakeNextIdStr());
            user.setCreateTime(LocalDateTime.now());
            user.setUpdateTime(LocalDateTime.now());
            Boolean insertuser = userMapper.insertUser(user);
            if (!insertuser) {
                throw new RuntimeException("添加失败");
            }
            Boolean insertNotificationSettings = notificationSettingsService.insertNotificationSettings(user.getId());
            if (!insertNotificationSettings){
                throw new RuntimeException("新增默认设置失败");
            }
            userVo.setIsFirst(true);
        }

        if (StringUtils.isEmpty(user.getName()) || StringUtils.isEmpty(user.getBirthday()) || StringUtils.isEmpty(user.getGender())) {
            userVo.setIsFirst(true);
        }
        DateTime iat = DateUtil.date();
        DateTime exp = DateUtil.offset(iat, DateField.HOUR, 24);
        Map<String, Object> payload = new HashMap<>();
        payload.put("id", user.getId());
        payload.put("phone",user.getPhone());
        //签发时间
        payload.put(JWTPayload.ISSUED_AT,iat);
        //失效时间
//        payload.put(JWTPayload.EXPIRES_AT,exp);
        //生效时间
        payload.put(JWTPayload.NOT_BEFORE, iat);
        String token = JWTUtil.createToken(payload,"tanhua".getBytes());
        BeanUtils.copyProperties(userVo, user);
        userVo.setToken(token);
        return userVo;
    }

    @Override
    public Boolean sendMessage(UserDto userDto) {
        Integer integer = ValidateCodeUtils.generateValidateCode(6);
        log.info("短信登录验证码：{}", integer);
        redisTemplate.opsForValue().setIfAbsent("tanhuaMsg:" + userDto.getPhone(), integer.toString(), 60, TimeUnit.SECONDS);
        return true;
    }


    @Override
    public Boolean updateInfo(UserDto userDto) {
        User user = userMapper.selectById(ThreadLocalUtil.getId());
        if (user == null) {
            throw new RuntimeException("手机号不存在");
        }
        userDto.setId(user.getId());
        BeanUtils.copyProperties(userDto, user);
        String birthday = userDto.getBirthday();
        String pattern="\\d{4}-\\d{2}-\\d{2}";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(birthday);
        Boolean update=false;
        if(m.find()){
            user.setUpdateTime(LocalDateTime.now());
            update = userMapper.updateById(user);
        }else {
            throw new RuntimeException("你输入的生日有误");
        }
        return update;
    }



    @Override
    public Boolean verifyUpdatePhoneMessage(UserDto userDto) {
        String code = redisTemplate.opsForValue().get("tanhuaMsg:" + userDto.getPhone());
        if (StringUtils.isEmpty(code)) {
            throw new RuntimeException("未发生验证码，或验证码已到期");
        }
        if (code.equals(userDto.getCode())) {
            redisTemplate.opsForValue().setIfAbsent("tanhuaUpdatePhone:" + userDto.getPhone(), JSON.toJSONString(userDto), 180, TimeUnit.SECONDS);
            return true;
        }
        return false;
    }

    @Override
    public Boolean updatePhone(UserDto userDto) {
        if (StringUtils.isEmpty(userDto.getPhone()) || StringUtils.isEmpty(userDto.getNewPhone()) || StringUtils.isEmpty(userDto.getCode())) {
            throw new RuntimeException("新旧手机号不能为空");
        }

        String msg = redisTemplate.opsForValue().get("tanhuaMsg:" + userDto.getNewPhone());
        if (!userDto.getCode().equals(msg)) {
            throw new RuntimeException("未发送验证码或验证码已过期或验证码不正确");
        }
        String s = redisTemplate.opsForValue().get("tanhuaUpdatePhone:" + userDto.getPhone());
        if (StringUtils.isEmpty(s)) {
            throw new RuntimeException("未验证旧手机或旧手机验证已过期");
        }

        UserDto userDtoInRedis = JSON.parseObject(s, UserDto.class);

        if (userDto.getPhone().equals(userDtoInRedis.getPhone())) {
            User userInDB = userMapper.selectByPhone(userDto.getPhone());
            if (ObjectUtil.isEmpty(userInDB)) {
                throw new RuntimeException("找不到该手机用户");
            }
            User user = new User();
            user.setPhone(userDto.getNewPhone());
            user.setId(userInDB.getId());
            user.setUpdateTime(LocalDateTime.now());
            return userMapper.updatePhone(user);
        }

        return false;
    }

    @Override
    public User selectById(String likeId) {
        return userMapper.selectById(likeId);
    }

    @Override
    public List<RecommendVo> selectRecommend(Double longitude, Double latitude) {
        LocationDto locationDto = new LocationDto();
        locationDto.setLongitude(longitude);
        locationDto.setLatitude(latitude);
        locationDto.setDistance(50.0);
        GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = locationService.selectLocation(locationDto);
        List<String> ids=new ArrayList<>();
        geoResults.getContent().forEach(
                s->{
                    String id = s.getContent().getName();
                    ids.add(id);
                }
        );
        if(ids.isEmpty()){
            throw new RuntimeException("没有找到周围的用户");
        }
        List<User> users=userMapper.selectByIds(ids);
        return BeanUtil.copyToList(users, RecommendVo.class);
    }

    @Override
    public List<UserVo> selectByIds(List<String> ids) {
        List<String> idList=new ArrayList<>(ids);
        List<User> users = userMapper.selectByIds(idList);
        List<UserVo> userVos = BeanUtil.copyToList(users, UserVo.class);

        return userVos;
    }


}
